/*---------------------------------------------------------------------*\
|			Compression / Decompression routines
\*---------------------------------------------------------------------*/

#include "compression.h"

namespace Tablebases
{

// extracts WDL info from DTM block
extern inline unsigned 	
dtm2WDL(dtm_t dtm)
{
	return (unsigned) dtm & 3;
}	

// compresses wdl record and depth to end to one value
extern inline dtm_t  WDL2dtm(unit_t wdl, unit_t depth)
{
	return (dtm_t)(depth << 2) | (wdl & 3);
}

// decompresses DTM block to WDL block
extern void			
dtm_block_2_wdl_block(dtm_block_t *g, wdl_block_t *w, size_t n)
{
	int width = 2;
	int shifting;
	size_t i;
	int j;
	unsigned int x ,y;
	 dtm_t *s = g->p_arr;
	unit_t *d = w->p_arr;

	for (i = 0, y = 0; i < n; i++) {
		j =  i & 3; /* modulo WDL_entries_per_unit */
		x = dtm2WDL(s[i]);
		shifting = j * width;
		y |= (x << shifting);		
		
		if (j == 3) {
			d[i/WDL_entries_per_unit] = (unit_t) y;
			y = 0;
		}
	}

	if (0 != (n & 3)) { /* not multiple of 4 */
		d[(n-1)/WDL_entries_per_unit] = (unit_t) y; /* save the rest     */
		y = 0;
	}

	return;
}	

// compresses WDL block and depth buffer to the sigle DTM block 
extern void wdl_block_2_dtm_block(dtm_block* r, wdl_block_t* w, unit_t * depthBuffer, size_t n)
{
	// set pointers
	dtm_t *d = r->p_arr;
	unit_t *s = w->p_arr;
	int index = 0;
	
	// iterate through all WDL entries
	for(int i = 0; i < n; i++)
	{
		int shift = i & 3; // modulo 2
		shift *= 2;
		unit_t wdl = ((s[index] >> shift) & 3);
		unit_t depth = depthBuffer[i];
		
		dtm_t dtm = WDL2dtm(wdl, depth);
		
		d[i] = dtm;
		
		if(i % 4 == 0)
		{
			index++;
		}
	}
}


}
